﻿using System;
using System.Drawing.Imaging;
using SHVS.Components;
using SHVS.DisplayData;
using VLIB28D.Geometry3D;
using VLIB2D.Geometry2D;

namespace GMPP.utils
{
    public class HeightMap
    {
        public HeightMap(BitmapData bmd, double width, double length, double heigth, string texStr)
        {
            Width = width;
            Length = length;
            Height = heigth;

            PicHeight = bmd.Height;
            PicWidth = bmd.Width;
            TexStr = texStr;
            Bmd = bmd;
            GetHeihtMap();
        }



        #region HeightMap 属性

        public float HeightMax { get; set; }

        public float HeightMin { get; set; }

        public float[,] Heights { get; set; }


        public string TexStr { get; set; }


        public double Width { get; set; }

        public double Length { get; set; }

        public double Height { get; set; }

        public int PicWidth { get; set; }

        public int PicHeight { get; set; }

        public BitmapData Bmd { get; set; }

        public float HeightRatio
        {
            get { return (float)Height / (HeightMax - HeightMin); }
        }

        public float WidthRatio
        {
            get { return (float)Width / PicWidth; }
        }

        public float LengthRatio
        {
            get { return (float)Length / PicHeight; }
        }

        public double[] Vertices { get; private set; }
        public double[] TexCoords { get; set; }
        public double[] Normals { get; set; }
        public uint[] Indices { get; set; }

        #endregion

        #region 运算结果~~

        public Point3D[,] Colors { get; set; }

        public Point3D[,] Point3Ds { get; set; }

        public Point2D[,] UvPoints { get; set; }

        public Vector3D[,] UnitNormalVectors { get; set; }

        public Vertex5D[,] Vertices5D { get; set; }

        public Triangles3D PointTrianles { get; set; }

        public Triangles2D UvTrianles { get; set; }

        public Triangles5D Triangle5Ds { get; set; }

        public Mesh Mesh { get; set; }

        #endregion

        private void GetHeihtMap()
        {
            InitData();
            GetPoints();


            BuildMesh();
            // Mesh = Triangle5Ds.ToMesh();
        }


        private void BuildMesh()
        {
            PointTrianles = new Triangles3D();
            UvTrianles = new Triangles2D();
            Triangle5Ds = new Triangles5D();
            Indices = new uint[(PicWidth - 1) * (PicHeight - 1) * 2 * 3];
            for (var j = 0; j < PicHeight - 1; j++)
            {
                for (var i = 0; i < PicWidth - 1; i++)
                {

                    Indices[6 * (j * (PicWidth - 1) + i) + 0] = Convert.ToUInt32(j * PicWidth + i);
                    Indices[6 * (j * (PicWidth - 1) + i) + 1] = Convert.ToUInt32((j + 1) * PicWidth + i);
                    Indices[6 * (j * (PicWidth - 1) + i) + 2] = Convert.ToUInt32((j + 1) * PicWidth + (i + 1));
                    Indices[6 * (j * (PicWidth - 1) + i) + 3] = Convert.ToUInt32(j * PicWidth + i);
                    Indices[6 * (j * (PicWidth - 1) + i) + 4] = Convert.ToUInt32((j + 1) * PicWidth + (i + 1));
                    Indices[6 * (j * (PicWidth - 1) + i) + 5] = Convert.ToUInt32(j * PicWidth + (i + 1));


                    var leftT5D = new Triangle5D(Vertices5D[i, j], Vertices5D[i, j + 1], Vertices5D[i + 1, j + 1]) { Material = TexStr };
                    //var leftUnitNormal = leftT5D.UnitNormalVector();
                    //Vertices5D[i, j].NormalsVector.SetTo(UnitNormalVectors[i, j].UnitVector + leftUnitNormal);
                    //Vertices5D[i, j + 1].NormalsVector.SetTo(UnitNormalVectors[i, j + 1].UnitVector + leftUnitNormal);
                    //Vertices5D[i + 1, j + 1].NormalsVector.SetTo(UnitNormalVectors[i + 1, j + 1].UnitVector + leftUnitNormal);


                    var rightT5D = new Triangle5D(Vertices5D[i, j], Vertices5D[i + 1, j + 1], Vertices5D[i + 1, j]) { Material = TexStr };
                    //var rightUnitNormal = rightT5D.UnitNormalVector();
                    //Vertices5D[i, j].NormalsVector.SetTo(UnitNormalVectors[i, j].UnitVector + rightUnitNormal);
                    //Vertices5D[i + 1, j + 1].NormalsVector.SetTo(UnitNormalVectors[i + 1, j + 1].UnitVector + rightUnitNormal);
                    //Vertices5D[i + 1, j].NormalsVector.SetTo(UnitNormalVectors[i + 1, j].UnitVector + rightUnitNormal);


                    Triangle5Ds.Add(leftT5D, "");
                    Triangle5Ds.Add(rightT5D, "");
                    // Triangle5Ds.GetBox();
                }
            }
        }



        private void GetPoints()
        {
            Point3Ds = new Point3D[PicWidth, PicHeight];
            UvPoints = new Point2D[PicWidth, PicHeight];
            UnitNormalVectors = new Vector3D[PicWidth, PicHeight];
            Vertices5D = new Vertex5D[PicWidth, PicHeight];

            Vertices = new double[PicHeight * PicWidth * 3];
            TexCoords = new double[PicHeight * PicWidth * 2];
            Normals = new double[PicHeight * PicWidth * 3];

            for (int j = 0; j < PicHeight; j++)
            {
                for (int i = 0; i < PicWidth; i++)
                {
                    var x = i * WidthRatio - Width / 2;
                    var y = Heights[i, j] * HeightRatio;
                    var z = j * LengthRatio - Length / 2;
                    var u = i / (float)PicWidth;
                    var v = j / (float)PicHeight;

                    Vertices[3 * (j * PicWidth + i) + 0] = x;
                    Vertices[3 * (j * PicWidth + i) + 1] = y;
                    Vertices[3 * (j * PicWidth + i) + 2] = z;

                    TexCoords[2 * (j * PicWidth + i) + 0] = u;
                    TexCoords[2 * (j * PicWidth + i) + 1] = v;

                    Normals[3 * (j * PicWidth + i) + 0] = 0;
                    Normals[3 * (j * PicWidth + i) + 1] = 0;
                    Normals[3 * (j * PicWidth + i) + 2] = 0;
                    Point3Ds[i, j] = new Point3D
                        {
                            X = x,
                            Y = y,
                            Z = z
                        };
                    UvPoints[i, j] = new Point2D
                        {
                            X = u,
                            Y = v
                        };
                    UnitNormalVectors[i, j] = new Vector3D(0, 1, 0);
                    Vertices5D[i, j] = new Vertex5D(Point3Ds[i, j], UvPoints[i, j], UnitNormalVectors[i, j]);
                }
            }
        }

        private unsafe void InitData()
        {
            Heights = new float[PicWidth, PicHeight];

            HeightMax = float.MinValue;

            HeightMin = float.MaxValue;
            Colors = new Point3D[PicWidth, PicHeight];

            var ptr = (byte*)(Bmd.Scan0);
            for (int j = 0; j < PicHeight; j++)
            {
                for (int i = 0; i < PicWidth; i++)
                {
                    Colors[i, j] = new Point3D(ptr[0] / 256.0, ptr[1] / 256.0, ptr[2] / 256.0);

                    var temp = (byte)(0.299 * ptr[2] + 0.587 * ptr[1] + 0.114 * ptr[0]);

                    var height = (float)temp;
                    Heights[i, j] = height;
                    if (height > HeightMax)
                    {
                        HeightMax = height;
                    }
                    if (height < HeightMin)
                    {
                        HeightMin = height;
                    }
                    ptr[0] = ptr[1] = ptr[2] = temp;
                    ptr += 3; //Format24bppRgb格式每个像素占3字节
                }
                ptr += Bmd.Stride - Bmd.Width * 3; //每行读取到最后“有用”数据时，跳过未使用空间XX
            }
        }
    }
}

#region 遗弃代码

/* var leftT3D = new Triangle3D
                         {
                             P1 = Point3Ds[i, j],
                             P2 = Point3Ds[i, j + 1],
                             P3 = Point3Ds[i + 1, j + 1],
                             V1 = UnitNormalVectors[i, j],
                             V2 = UnitNormalVectors[i, j + 1],
                             V3 = UnitNormalVectors[i + 1, j + 1],
                             Texture = TexStr
                         };
                     var rightT3D = new Triangle3D
                         {
                             P1 = Point3Ds[i, j],
                             P2 = Point3Ds[i + 1, j + 1],
                             P3 = Point3Ds[i + 1, j],
                             V1 = UnitNormalVectors[i, j],
                             V2 = UnitNormalVectors[i + 1, j + 1],
                             V3 = UnitNormalVectors[i + 1, j],
                             Texture = TexStr + "right"
                         };

                     var leftT2D = new Triangle2D
                         {
                             P1 = UvPoints[i, j],
                             P2 = UvPoints[i, j + 1],
                             P3 = UvPoints[i + 1, j + 1],
                             Texture = TexStr
                         };
                     var rightT2D = new Triangle2D
                         {
                             P1 = UvPoints[i, j],
                             P2 = UvPoints[i + 1, j + 1],
                             P3 = UvPoints[i + 1, j],
                             Texture = TexStr + "right"
                         };*/
#endregion